#include "eveCommon.h"
#include "eveBmp.h"

namespace eve
{
	Bmp::Bmp()
		: m_pData(NULL)
		, m_size(0)
		, m_bitpixels(0)
		, m_width(0)
		, m_height(0)
		, m_blockXNum(0)
		, m_blockYNum(0)
	{
	}

	Bmp::~Bmp()
	{
		this->ReleaseTextures();
	}

	void Bmp::Compute()
	{
		m_blockXNum = GetBlockNum(m_width);
		m_blockYNum = GetBlockNum(m_height);

		//TEXTUREWIDTH
	}

	void Bmp::ReleaseTextures()
	{
		for( std::vector<Texture*>::iterator iter = m_TextureList.begin(); iter != m_TextureList.end(); ++iter )
		{
			TextureManager::GetSingleton()->ReleaseTexture((*iter));
		}
		m_TextureList.clear();
	}

	stPointI Bmp::GetTextureSize(uint8 blockx,uint8 blocky) const
	{
		
		stPointI pt(TEXTUREWIDTH,TEXTUREHEIGHT);
		if( blockx == m_blockXNum - 1 )
		{
			pt.x = GetTailWidth(m_width);
		}
		if ( blocky == m_blockYNum - 1 )
		{
			pt.y = GetTailWidth(m_height);
		}
		return pt;
	}

	stPointI Bmp::GetBlockByBmpOffset(uint16 offsetx,uint16 offsety) const
	{
		return stPointI(offsetx&0xff00,offsety&0xff00);
	}
	
	stRectI Bmp::GetBlockRect(uint8 blockx,uint8 blocky) const
	{
		uint16 x = blockx * TEXTUREWIDTH;
		uint16 y = blocky * TEXTUREHEIGHT;
		const stPointI& size = GetTextureSize(blockx,blocky);
		return stRectI(x,y,x+size.x,y+size.y);
	}

	std::vector<Texture*> Bmp::GenerateTexture()
	{
		ReleaseTextures();
		Compute();
		D3DFORMAT format = GetTextureFormat(m_bitpixels);
		size_t texnum = m_blockXNum * m_blockYNum;
		stPointI base;
		m_TextureList.resize(texnum,0);
		::Texture* ptmptex = TextureManager::GetSingleton()->FindAndCreateTexture(
					TEXTUREWIDTH,TEXTUREHEIGHT,0,format,D3DPOOL_SYSTEMMEM);
		for( uint8 i = 0 ; i < m_blockYNum ; ++i )
		{
			for( uint8 j = 0; j < m_blockXNum ; ++j )
			{
				stPointI texsize = GetTextureSize(j,i);
				
				::Texture* pdsttex = TextureManager::GetSingleton()->FindAndCreateTexture(
					TEXTUREWIDTH,TEXTUREHEIGHT,0,format,D3DPOOL_DEFAULT);
				ID3DTexture* pd3dtex = ptmptex->GetD3DTexture();
				D3DLOCKED_RECT lr;
				pd3dtex->LockRect(0,&lr,NULL,0);
				
				if( m_bitpixels == 16 )
				{
					WORD *p = (WORD*)lr.pBits;
					WORD* src = (WORD*)m_pData;
					for( uint16 y = 0 ; y < texsize.y ; ++y )
					for( uint16 x = 0 ; x < texsize.x; ++x )
					{
						uint32 index = y * lr.Pitch/2 + x;
						p[index] = src[(base.y+y) * m_width+base.x+x];
						
					}
				}
				else if( m_bitpixels = 32 )
				{
					DWORD *p = (DWORD*)lr.pBits;
					DWORD* src = (DWORD*)m_pData;
					for( uint16 y = 0 ; y < texsize.y ; ++y )
					for( uint16 x = 0 ; x < texsize.x; ++x )
					{
						uint32 index = y * lr.Pitch/4 + x;
						p[index] = src[(base.y+y) * m_width+base.x+x];
						
					}
				}
				
				pd3dtex->UnlockRect(0);
				
				ID3DTexture* pdstd3dtex = pdsttex->GetD3DTexture();
				RenderSystem::GetSingleton()->UpdateTexture(pd3dtex,pdstd3dtex);
				base.x += texsize.x;
				this->m_TextureList[j + i * m_blockXNum] = (pdsttex);
				
			}
			base.x = 0;
			base.y += TEXTUREHEIGHT;
		}
		TextureManager::GetSingleton()->ReleaseTexture(ptmptex);
		return m_TextureList;
	}

	void Bmp::Render(int x ,int y,DWORD color)
	{
		if( m_TextureList.empty() || m_TextureList[0]->GetD3DTexture() == NULL ) 
			GenerateTexture();
		
		int xoffset = x;
		int yoffset = y;
		size_t index = 0;

		
		RenderSystem::GetSingleton()->SetDrawState();

		for( uint8 i = 0 ; i < m_blockYNum ; ++i )
		{
			for( uint8 j = 0 ; j < m_blockXNum ; ++j )
			{
				stPointI texsize = GetTextureSize(j,i);
				
				Texture* ptex = m_TextureList[j+i*m_blockXNum];
				RenderSystem::GetSingleton()->Draw(stRectI(xoffset,yoffset,texsize.x+xoffset,texsize.y+yoffset),
					stRectI(0,0,texsize.x,texsize.y),
						color,
						ptex);


				xoffset += TEXTUREWIDTH;
			}
			xoffset = x;
			yoffset += TEXTUREHEIGHT;
		}
	}
	void Bmp::Render(int x,int y,DWORD color,const stRectI& rc,const stRectI& texturerc)
	{
		if( m_TextureList.empty() || m_TextureList[0]->GetD3DTexture() == NULL ) 
			GenerateTexture();
		RenderSystem::GetSingleton()->SetDrawState();
		const Real scalex = Real(rc.Width())/Real(texturerc.Width());
		const Real scaley = Real(rc.Height())/Real(texturerc.Height());
		int beginx = x;
		int beginy = y;
		const stPointI& startblock = this->GetBlockByBmpOffset(texturerc.left,texturerc.top);
		const stPointI& endblock = this->GetBlockByBmpOffset(texturerc.right,texturerc.bottom);
		for( long blocky = startblock.y ; blocky <= endblock.y ; ++blocky )
		{
			for( long blockx = startblock.x ; blockx <= endblock.x ; ++blockx )
			{
				
				const stRectI& blocktexturerc = this->GetBlockRect(blockx,blocky);
				const stRectI& intersecttexturerc = (blocktexturerc & texturerc);
				const stRectI  blockrc(0,0,intersecttexturerc.Width()*scalex,intersecttexturerc.Height()*scaley);
				RenderBlockWithScale(beginx,beginy,color,blockx,blocky,blockrc,intersecttexturerc,stPointF(scalex,scaley));
				beginx += TEXTUREWIDTH * scalex;
			}
			beginy += TEXTUREHEIGHT * scaley;
		}
	}
	void Bmp::Render(int x,int y,DWORD color,const stRectI& texturerc)
	{
		if( m_TextureList.empty() || m_TextureList[0]->GetD3DTexture() == NULL ) 
			GenerateTexture();
		RenderSystem::GetSingleton()->SetDrawState();
		int beginx = x;
		int beginy = y;
		const stPointI& startblock = this->GetBlockByBmpOffset(texturerc.left,texturerc.top);
		const stPointI& endblock = this->GetBlockByBmpOffset(texturerc.right,texturerc.bottom);
		for( long blocky = startblock.y ; blocky <= endblock.y ; ++blocky )
		{
			for( long blockx = startblock.x ; blockx <= endblock.x ; ++blockx )
			{
				
				const stRectI& blocktexturerc = this->GetBlockRect(blockx,blocky);
				const stRectI& intersecttexturerc = (blocktexturerc & texturerc);
				const stRectI  blockrc(0,0,intersecttexturerc.Width(),intersecttexturerc.Height());
				RenderBlockNoScale(beginx,beginy,color,blockx,blocky,blockrc,intersecttexturerc);
				beginx += TEXTUREWIDTH;
			}
			beginy += TEXTUREHEIGHT;
		}
	}

	void Bmp::RenderBlockWithScale(int x,int y,DWORD color,uint8 blockx,uint8 blocky,
		const stRectI &rc,
		const stRectI& texturerc,
		const stPointF& scale)
	{
		stRectI texrc;
		texrc.left = (texturerc.left & 0xff);
		texrc.top = (texturerc.top & 0xff);
		texrc.right = (texturerc.right & 0xff);
		texrc.bottom = (texturerc.bottom & 0xff);
		
		Texture* ptex = m_TextureList[blockx+blocky*m_blockXNum];
		
		RenderSystem::GetSingleton()->Draw(stRectI(x,y,x+rc.Width(),y+rc.Height()),
						texrc,
						color,
						ptex,
						scale);
	}

	void Bmp::RenderBlockNoScale(int x,int y,DWORD color,uint8 blockx,uint8 blocky,
		const stRectI &rc,
		const stRectI& texturerc)
	{
		stRectI texrc;
		texrc.left = (texturerc.left & 0xff);
		texrc.top = (texturerc.top & 0xff);
		texrc.right = (texturerc.right & 0xff);
		texrc.bottom = (texturerc.bottom & 0xff);
		
		Texture* ptex = m_TextureList[blockx+blocky*m_blockXNum];
		
		RenderSystem::GetSingleton()->Draw(stRectI(x,y,x+rc.Width(),y+rc.Height()),
						texrc,
						color,
						ptex);
	}

}